package gz

import (
	"bytes"
	stdContext "context"
	"crypto/tls"
	"errors"
	"fmt"
	"gitee.com/gzcloud/gzcloud/const"
	"gitee.com/gzcloud/gzcloud/resource"
	"github.com/tencentyun/scf-go-lib/cloudfunction"
	"github.com/tencentyun/scf-go-lib/events"
	"io"
	"io/ioutil"
	stdLog "log"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/labstack/gommon/color"
	"github.com/labstack/gommon/log"
	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
)

type (
	// Application is the top-level framework instance.
	Application struct {
		// 初始化时的时间戳
		InitTime time.Time
		// 结束时的时间戳
		EndTime time.Time

		common
		// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
		// listener address info (on which interface/port was listener binded) without having data races.
		startupMutex  sync.RWMutex
		StdLogger     *stdLog.Logger
		colorer       *color.Color
		premiddleware []MiddlewareFunc
		middleware    []MiddlewareFunc
		middlewareMap map[string]MiddlewareFunc
		maxParam      *int
		// 路由
		router *Router
		// 路由映射 string:Router
		routers         map[string]*Router
		notFoundHandler HandlerFunc
		// 用以缓存context
		pool             sync.Pool
		Server           *http.Server
		TLSServer        *http.Server
		Listener         net.Listener
		TLSListener      net.Listener
		AutoTLSManager   autocert.Manager
		DisableHTTP2     bool
		Debug            bool
		HideBanner       bool
		HidePort         bool
		HTTPErrorHandler HTTPErrorHandler
		Binder           Binder
		Validator        Validator
		Renderer         Renderer
		Logger           Logger
		IPExtractor      IPExtractor
		ListenerNetwork  string

		//	配置文件
		Config *resource.GzconfigStruct
	}

	// Route contains a handler and information for matching against requests.
	Route struct {
		Method string `json:"method"`
		Path   string `json:"path"`
		Name   string `json:"name"`
	}

	// HTTPError represents an error that occurred while handling a request.
	// HTTPError表示在处理请求时发生的错误。
	HTTPError struct {
		Code    int         `json:"-"`
		Message interface{} `json:"message"`
		// 存储外部依赖项返回的错误
		Internal error `json:"-"` // Stores the error returned by an external dependency
	}

	// MiddlewareFunc defines a function to process middleware.
	// MiddlewareFunc定义了处理中间件的功能。
	MiddlewareFunc func(HandlerFunc) HandlerFunc

	// HandlerFunc defines a function to serve HTTP requests.
	// HandlerFunc定义了一个服务于HTTP请求的函数。
	HandlerFunc func(Context) error

	// HTTPErrorHandler is a centralized HTTP error handler.
	// HTTPErrorHandler是集中式HTTP错误处理程序。
	HTTPErrorHandler func(error, Context)

	// Validator is the interface that wraps the Validate function.
	// 验证程序是包装Validate函数的接口。
	Validator interface {
		Validate(i interface{}) error
	}

	// Renderer is the interface that wraps the Render function.
	// Renderer是包装Render函数的接口。
	Renderer interface {
		Render(io.Writer, string, interface{}, Context) error
	}

	// Map defines a generic map of type `map[string]interface{}`.
	Map map[string]interface{}

	// Common struct for Application & Group.
	common struct{}
)

// HTTP methods
// NOTE: Deprecated, please use the stdlib constants directly instead.
const (
	CONNECT = http.MethodConnect
	DELETE  = http.MethodDelete
	GET     = http.MethodGet
	HEAD    = http.MethodHead
	OPTIONS = http.MethodOptions
	PATCH   = http.MethodPatch
	POST    = http.MethodPost
	// PROPFIND = "PROPFIND"
	PUT   = http.MethodPut
	TRACE = http.MethodTrace
)

const (
	MODE_TYPE_SCF   = "scf"
	MODE_TYPE_WEB   = "web"
	URL_PREFIX_ROOT = "/"
)

// MIME types
const (
	MIMEApplicationJSON                  = "application/json"
	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + charsetUTF8
	MIMEApplicationJavaScript            = "application/javascript"
	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
	MIMEApplicationXML                   = "application/xml"
	// "application/xml; charset=UTF-8"
	MIMEApplicationXMLCharsetUTF8 = MIMEApplicationXML + "; " + charsetUTF8
	MIMETextXML                   = "text/xml"
	MIMETextXMLCharsetUTF8        = MIMETextXML + "; " + charsetUTF8
	MIMEApplicationForm           = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf       = "application/protobuf"
	MIMEApplicationMsgpack        = "application/msgpack"
	MIMETextHTML                  = "text/html"
	MIMETextHTMLCharsetUTF8       = MIMETextHTML + "; " + charsetUTF8
	MIMETextPlain                 = "text/plain"
	MIMETextPlainCharsetUTF8      = MIMETextPlain + "; " + charsetUTF8
	MIMEMultipartForm             = "multipart/form-data"
	MIMEOctetStream               = "application/octet-stream"
)

const (
	charsetUTF8 = "charset=UTF-8"
	// PROPFIND Method can be used on collection and property resources.
	PROPFIND = "PROPFIND"
	// REPORT Method can be used to get information about a resource, see rfc 3253
	REPORT = "REPORT"
)

// Headers
const (
	HeaderAccept              = "Accept"
	HeaderAcceptEncoding      = "Accept-Encoding"
	HeaderAllow               = "Allow"
	HeaderAuthorization       = "Authorization"
	HeaderContentDisposition  = "Content-Disposition"
	HeaderContentEncoding     = "Content-Encoding"
	HeaderContentLength       = "Content-Length"
	HeaderContentType         = "Content-Type"
	HeaderCookie              = "Cookie"
	HeaderSetCookie           = "Set-Cookie"
	HeaderIfModifiedSince     = "If-Modified-Since"
	HeaderLastModified        = "Last-Modified"
	HeaderLocation            = "Location"
	HeaderUpgrade             = "Upgrade"
	HeaderVary                = "Vary"
	HeaderWWWAuthenticate     = "WWW-Authenticate"
	HeaderXForwardedFor       = "X-Forwarded-For"
	HeaderXForwardedProto     = "X-Forwarded-Proto"
	HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
	HeaderXForwardedSsl       = "X-Forwarded-Ssl"
	HeaderXUrlScheme          = "X-Url-Scheme"
	HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
	HeaderXRealIP             = "X-Real-IP"
	HeaderXRequestID          = "X-Request-ID"
	HeaderXRequestedWith      = "X-Requested-With"
	HeaderServer              = "Server"
	HeaderOrigin              = "Origin"

	// Access control
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"

	// Security
	HeaderStrictTransportSecurity         = "Strict-Transport-Security"
	HeaderXContentTypeOptions             = "X-Content-Type-Options"
	HeaderXXSSProtection                  = "X-XSS-Protection"
	HeaderXFrameOptions                   = "X-Frame-Options"
	HeaderContentSecurityPolicy           = "Content-Security-Policy"
	HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
	HeaderXCSRFToken                      = "X-CSRF-Token"
	HeaderReferrerPolicy                  = "Referrer-Policy"
)

const (
	// Version of Application
	Version     = "0.0.1"
	EchoVersion = "4.1.17"
	website     = "https://gitee.com/gzcloud/gzcloud"
	// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Application
	banner = `
                         .__                      .___
   ____ ________  ____  |  |    ____   __ __   __| _/
  / ___\\___   /_/ ___\ |  |   /  _ \ |  |  \ / __ |
 / /_/  >/    / \  \___ |  |__(  <_> )|  |  // /_/ |
 \___  //_____ \ \___  >|____/ \____/ |____/ \____ |
/_____/       \/     \/                           \/          %s
高性能的go web框架，兼容SCF, mode=%s, active=%s
基于echo v%s，gzcloud：%s
____________________________________O/_O/_O/_____
`
)

var (
	methods = [...]string{
		http.MethodConnect,
		http.MethodDelete,
		http.MethodGet,
		http.MethodHead,
		http.MethodOptions,
		http.MethodPatch,
		http.MethodPost,
		PROPFIND,
		http.MethodPut,
		http.MethodTrace,
		REPORT,
	}
)

// Errors
var (
	ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)
	ErrNotFound                    = NewHTTPError(http.StatusNotFound)
	ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)
	ErrForbidden                   = NewHTTPError(http.StatusForbidden)
	ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)
	ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
	ErrTooManyRequests             = NewHTTPError(http.StatusTooManyRequests)
	ErrBadRequest                  = NewHTTPError(http.StatusBadRequest)
	ErrBadGateway                  = NewHTTPError(http.StatusBadGateway)
	ErrInternalServerError         = NewHTTPError(http.StatusInternalServerError)
	ErrRequestTimeout              = NewHTTPError(http.StatusRequestTimeout)
	ErrServiceUnavailable          = NewHTTPError(http.StatusServiceUnavailable)
	ErrValidatorNotRegistered      = errors.New("validator not registered")
	ErrRendererNotRegistered       = errors.New("renderer not registered")
	ErrInvalidRedirectCode         = errors.New("invalid redirect status code")
	ErrCookieNotFound              = errors.New("cookie not found")
	ErrInvalidCertOrKeyType        = errors.New("invalid cert or key type, must be string or []byte")
	ErrInvalidListenerNetwork      = errors.New("invalid listener network")
)

// Error handlers
var (
	NotFoundHandler = func(c Context) error {
		return ErrNotFound
	}

	MethodNotAllowedHandler = func(c Context) error {
		return ErrMethodNotAllowed
	}
)

// New creates an instance of Application.
func Initialize(config *resource.GzconfigStruct) (app *Application) {
	initTime := time.Now()

	var _config *resource.GzconfigStruct
	if config == nil {
		// TODO 获取配置文件或配置数据
		//_config = resource.GetConfig()
		_config = default_config
	} else {
		_config = config
	}

	// 初始化框架
	app = &Application{
		// 初始化时的时间戳
		InitTime: initTime,
		// *resource.GzconfigStruct
		Config: _config,
		// 初始化 server
		Server:    new(http.Server),
		TLSServer: new(http.Server),
		//
		AutoTLSManager: autocert.Manager{
			Prompt: autocert.AcceptTOS,
		},
		// 初始化日志 & 颜色
		Logger:          log.New(gzconst.NAME),
		colorer:         color.New(),
		maxParam:        new(int),
		ListenerNetwork: "tcp",
	}

	// TODO 设置 banner
	if strings.EqualFold(app.Config.Banner.Mode, gzconst.OFF) {
		app.HideBanner = true
	} else if strings.EqualFold(app.Config.Banner.Mode, gzconst.ON) {
		app.HideBanner = false
	}

	app.Server.Handler = app
	app.TLSServer.Handler = app
	app.HTTPErrorHandler = app.DefaultHTTPErrorHandler
	app.Binder = &DefaultBinder{}

	// 设置日志：
	app.setLog(config)

	app.StdLogger = stdLog.New(app.Logger.Output(), app.Logger.Prefix()+": ", 0)
	// context缓存的获取方法
	// 定义函数，返回interface{}
	app.pool.New = func() interface{} {
		return app.NewContext(nil, nil)
	}
	app.router = NewRouter(app)
	app.routers = map[string]*Router{}

	return
}

func (app *Application) setLog(config *resource.GzconfigStruct) {
	// TODO 日志级别，在yml中配置
	if config.Log.Format != "" {
		app.Logger.SetHeader(config.Log.Format)
	}
	if config.Log.Color != false {
		app.Logger.(*log.Logger).EnableColor()
	}

	// 级别
	if config.Log.Level == gzconst.EMPTY {
		//	默认
		app.Logger.SetLevel(log.ERROR)
	} else if strings.EqualFold(config.Log.Level, gzconst.LOG_LEVEL_DEBUG) {
		app.Logger.SetLevel(log.DEBUG)
	} else if strings.EqualFold(config.Log.Level, gzconst.LOG_LEVEL_INFO) {
		app.Logger.SetLevel(log.INFO)
	} else if strings.EqualFold(config.Log.Level, gzconst.LOG_LEVEL_ERROR) {
		app.Logger.SetLevel(log.ERROR)
	} else if strings.EqualFold(config.Log.Level, gzconst.LOG_LEVEL_ERR) {
		app.Logger.SetLevel(log.ERROR)
	}
}

// NewContext returns a Context instance.
func (app *Application) NewContext(r *http.Request, w http.ResponseWriter) Context {
	return &context{
		request:     r,
		response:    NewResponse(w, app),
		store:       make(Map),
		application: app,
		pvalues:     make([]string, *app.maxParam),
		handler:     NotFoundHandler,
	}
}

// Router returns the default router.
func (e *Application) Router() *Router {
	return e.router
}

// Routers returns the map of host => router.
func (e *Application) Routers() map[string]*Router {
	return e.routers
}



// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
// with status code.
func (app *Application) DefaultHTTPErrorHandler(err error, c Context) {
	he, ok := err.(*HTTPError)
	if ok {
		if he.Internal != nil {
			if herr, ok := he.Internal.(*HTTPError); ok {
				he = herr
			}
		}
	} else {
		he = &HTTPError{
			Code:    http.StatusInternalServerError,
			Message: http.StatusText(http.StatusInternalServerError),
		}
	}

	// Issue #1426
	code := he.Code
	message := he.Message
	if m, ok := he.Message.(string); ok {
		if app.Debug {
			message = Map{"message": m, "error": err.Error()}
		} else {
			message = Map{"message": m}
		}
	}// end if

	// Send response
	if !c.Response().Committed {
		if c.Request().Method == http.MethodHead { // Issue #608
			err = c.NoContent(he.Code)
		} else {
			err = c.JSON(code, message)
		}
		if err != nil {
			app.Logger.Error(err)
		}
	}// end if
}


// Pre adds middleware to the chain which is run before router.
func (app *Application) Pre(middleware ...MiddlewareFunc) {
	app.premiddleware = append(app.premiddleware, middleware...)
}

// Use adds middleware to the chain which is run after router.
// 从app.middlewareMap获取middleware
func (app *Application) middlewareRest() {
	i := 0
	if len(app.middlewareMap) == 0 {
		app.middleware = make([]MiddlewareFunc, 0)
	}
	values := make([]MiddlewareFunc, len(app.middlewareMap))
	for _, v := range app.middlewareMap {
		values[i] = v
		i++
	}
	app.middleware = values
}

// TODO 使用map，<string,type> 可以进行删除
func (app *Application) Remove(key string) {
	delete(app.middlewareMap, key)
	app.middlewareRest()
}
func (app *Application) AddMiddleware(key string, middleware MiddlewareFunc) {
	// app.middlewareMap
	// 判断key是否存在
	if app.middlewareMap == nil {
		app.middlewareMap = make(map[string]MiddlewareFunc)
	}
	app.middlewareMap[key] = middleware
	app.middlewareRest()
}

/*
Deprecate: 请使用 AddMiddleware 方法
*/
func (app *Application) Use(middleware ...MiddlewareFunc) {
	// app.middlewareMap
	app.middleware = append(app.middleware, middleware...)
}

// CONNECT registers a new CONNECT route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodConnect, path, h, m...)
}

// DELETE registers a new DELETE route for a path with matching handler in the router
// with optional route-level middleware.
func (app *Application) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodDelete, path, h, m...)
}

// GET registers a new GET route for a path with matching handler in the router
// with optional route-level middleware.
func (app *Application) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodGet, path, h, m...)
}

// HEAD registers a new HEAD route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodHead, path, h, m...)
}

// OPTIONS registers a new OPTIONS route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodOptions, path, h, m...)
}

// PATCH registers a new PATCH route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodPatch, path, h, m...)
}

// POST registers a new POST route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodPost, path, h, m...)
}

// PUT registers a new PUT route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodPut, path, h, m...)
}

// TRACE registers a new TRACE route for a path with matching handler in the
// router with optional route-level middleware.
func (app *Application) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
	return app.Add(http.MethodTrace, path, h, m...)
}

// Any registers a new route for all HTTP methods and path with matching handler
// in the router with optional route-level middleware.
func (app *Application) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
	routes := make([]*Route, len(methods))
	for i, m := range methods {
		routes[i] = app.Add(m, path, handler, middleware...)
	}
	return routes
}

// Match registers a new route for multiple HTTP methods and path with matching
// handler in the router with optional route-level middleware.
func (app *Application) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
	routes := make([]*Route, len(methods))
	for i, m := range methods {
		routes[i] = app.Add(m, path, handler, middleware...)
	}
	return routes
}

// Static registers a new route with path prefix to serve static files from the
// provided root directory.
func (app *Application) Static(prefix, root string) *Route {
	if root == "" {
		root = "." // For security we want to restrict to CWD.
	}
	return app.static(prefix, root, app.GET)
}

func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route {
	h := func(c Context) error {
		p, err := url.PathUnescape(c.Param("*"))
		if err != nil {
			return err
		}

		name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
		fi, err := os.Stat(name)
		if err != nil {
			// The access path does not exist
			return NotFoundHandler(c)
		}

		// If the request is for a directory and does not end with "/"
		p = c.Request().URL.Path // path must not be empty.
		if fi.IsDir() && p[len(p)-1] != '/' {
			// Redirect to ends with "/"
			return c.Redirect(http.StatusMovedPermanently, p+"/")
		}
		return c.File(name)
	}
		// Handle added routes based on trailing slash:
		// 	/prefix  => exact route "/prefix" + any route "/prefix/*"
		// 	/prefix/ => only any route "/prefix/*"
		if prefix != "" {
			if prefix[len(prefix)-1] == '/' {
				// Only add any route for intentional trailing slash
				return get(prefix+"*", h)
			}
			get(prefix, h)
		}
	return get(prefix+"/*", h)
}

func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route,
	m ...MiddlewareFunc) *Route {
	return get(path, func(c Context) error {
		return c.File(file)
	}, m...)
}

// File registers a new route with path to serve a static file with optional route-level middleware.
func (app *Application) File(path, file string, m ...MiddlewareFunc) *Route {
	return app.file(path, file, app.GET, m...)
}

func (app *Application) add(host, method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
	// https://github.com/serverlessplus/go/issues/2
	if strings.EqualFold(app.Config.Mode, MODE_TYPE_SCF) {
		// 如果配置：gz.mode = scf 则路由添加前缀
		path = URL_PREFIX_ROOT + app.Config.Name + path
	}
	name := handlerName(handler)
	router := app.findRouter(host)
	router.Add(method, path, func(c Context) error {
		h := applyMiddleware(handler, middleware...)
		return h(c)
	})
	r := &Route{
		Method: method,
		Path:   path,
		Name:   name,
	}
	app.router.routes[method+path] = r
	return r
}

// Add registers a new route for an HTTP method and path with matching handler
// in the router with optional route-level middleware.
func (app *Application) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
	return app.add("", method, path, handler, middleware...)
}

// Host creates a new router group for the provided host and optional host-level middleware.
func (app *Application) Host(name string, m ...MiddlewareFunc) (g *Group) {
	app.routers[name] = NewRouter(app)
	g = &Group{host: name, app: app}
	g.Use(m...)
	return
}

// Group creates a new router group with prefix and optional group-level middleware.
func (app *Application) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
	g = &Group{prefix: prefix, app: app}
	g.Use(m...)
	return
}

// URI generates a URI from handler.
func (app *Application) URI(handler HandlerFunc, params ...interface{}) string {
	name := handlerName(handler)
	return app.Reverse(name, params...)
}

// URL is an alias for `URI` function.
func (app *Application) URL(h HandlerFunc, params ...interface{}) string {
	return app.URI(h, params...)
}

// Reverse generates an URL from route name and provided parameters.
func (app *Application) Reverse(name string, params ...interface{}) string {
	uri := new(bytes.Buffer)
	ln := len(params)
	n := 0
	for _, r := range app.router.routes {
		if r.Name == name {
			for i, l := 0, len(r.Path); i < l; i++ {
				if (r.Path[i] == ':' || r.Path[i] == '*') && n < ln {
					for ; i < l && r.Path[i] != '/'; i++ {
					}
					uri.WriteString(fmt.Sprintf("%v", params[n]))
					n++
				}
				if i < l {
					uri.WriteByte(r.Path[i])
				}
			}
			break
		}
	}
	return uri.String()
}

// Routes returns the registered routes.
func (app *Application) Routes() []*Route {
	routes := make([]*Route, 0, len(app.router.routes))
	for _, v := range app.router.routes {
		routes = append(routes, v)
	}
	return routes
}

// AcquireContext returns an empty `Context` instance from the pool.
// You must return the context by calling `ReleaseContext()`.
func (app *Application) AcquireContext() Context {
	return app.pool.Get().(Context)
}

// ReleaseContext returns the `Context` instance back to the pool.
// You must call it after `AcquireContext()`.
func (app *Application) ReleaseContext(c Context) {
	app.pool.Put(c)
}

// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
func (app *Application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Acquire context
	c := app.pool.Get().(*context)
	c.Reset(r, w)

	h := NotFoundHandler

	if app.premiddleware == nil {
		app.findRouter(r.Host).Find(r.Method, r.URL.EscapedPath(), c)
		h = c.Handler()
		h = applyMiddleware(h, app.middleware...)
	} else {
		h = func(c Context) error {
			app.findRouter(r.Host).Find(r.Method, r.URL.EscapedPath(), c)
			h := c.Handler()
			h = applyMiddleware(h, app.middleware...)
			return h(c)
		}
		h = applyMiddleware(h, app.premiddleware...)
	}

	// Execute chain
	if err := h(c); err != nil {
		app.HTTPErrorHandler(err, c)
	}

	// Release context
	app.pool.Put(c)
}

var lambda *GzLambda

func scfHandleRequest(ctx stdContext.Context, request events.APIGatewayRequest) (events.APIGatewayResponse, error) {
	return lambda.ProxyWithContext(ctx, request)
}

// Start starts an HTTP server.
func (app *Application) Start(address string) error {
	app.startupMutex.Lock()
	if !app.HideBanner {

		// TODO 计划新增 app.Config.Banner.Path
		if app.Config.Banner.Text == "" {
			app.colorer.Printf(banner,
				app.colorer.Red("v"+Version),
				app.colorer.Blue(app.Config.Mode),
				app.colorer.Blue(app.Config.Active),
				app.colorer.Blue(EchoVersion),
				app.colorer.Blue(website))
		} else {
			app.colorer.Blue(app.Config.Banner.Text)
		}
	}

	// 判断mode是否为scf，如果为true 则使用适配器
	if strings.EqualFold(MODE_TYPE_SCF, app.Config.Mode) {
		// 如果时scf
		lambda = adapterInitialize(app)
		cloudfunction.Start(scfHandleRequest)

		// TODO 缺少环境判断
		return nil
	}

	// 因为只有web和scf，所以不用if判断
	app.Server.Addr = address
	if err := app.configureServer(app.Server); err != nil {
		app.startupMutex.Unlock()
		return err
	}
	app.startupMutex.Unlock()
	return app.serve()
}

// StartTLS starts an HTTPS server.
// If `certFile` or `keyFile` is `string` the values are treated as file paths.
// If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.
func (app *Application) StartTLS(address string, certFile, keyFile interface{}) (err error) {
	app.startupMutex.Lock()
	var cert []byte
	if cert, err = filepathOrContent(certFile); err != nil {
		app.startupMutex.Unlock()
		return
	}

	var key []byte
	if key, err = filepathOrContent(keyFile); err != nil {
		app.startupMutex.Unlock()
		return
	}

	s := app.TLSServer
	s.TLSConfig = new(tls.Config)
	s.TLSConfig.Certificates = make([]tls.Certificate, 1)
	if s.TLSConfig.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
		app.startupMutex.Unlock()
		return
	}

	app.configureTLS(address)
	if err := app.configureServer(s); err != nil {
		app.startupMutex.Unlock()
		return err
	}
	app.startupMutex.Unlock()
	return s.Serve(app.TLSListener)
}

func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
	switch v := fileOrContent.(type) {
	case string:
		return ioutil.ReadFile(v)
	case []byte:
		return v, nil
	default:
		return nil, ErrInvalidCertOrKeyType
	}
}

// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
func (app *Application) StartAutoTLS(address string) error {
	app.startupMutex.Lock()
	s := app.TLSServer
	s.TLSConfig = new(tls.Config)
	s.TLSConfig.GetCertificate = app.AutoTLSManager.GetCertificate
	s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto)

	app.configureTLS(address)
	if err := app.configureServer(s); err != nil {
		app.startupMutex.Unlock()
		return err
	}
	app.startupMutex.Unlock()
	return s.Serve(app.TLSListener)
}

func (e *Application) configureTLS(address string) {
	s := e.TLSServer
	s.Addr = address
	if !e.DisableHTTP2 {
		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
	}
}

// StartServer starts a custom http server.
func (app *Application) StartServer(s *http.Server) (err error) {
	app.startupMutex.Lock()
	if err := app.configureServer(s); err != nil {
		app.startupMutex.Unlock()
		return err
	}
	app.startupMutex.Unlock()
	return app.serve()
}
func (app *Application) configureServer(s *http.Server) (err error) {
	// Setup
	app.colorer.SetOutput(app.Logger.Output())
	s.ErrorLog = app.StdLogger
	s.Handler = app
	if app.Debug {
		app.Logger.SetLevel(log.DEBUG)
	}

	if s.TLSConfig == nil {
		if app.Listener == nil {
			app.Listener, err = newListener(s.Addr, app.ListenerNetwork)
			if err != nil {
				return err
			}
		}
		if !app.HidePort {
			//app.Logger.Infof("⇨ http server启动... on： %s\n", app.colorer.Green(app.Listener.Addr()))
			app.colorer.Printf("⇨ http server启动... on： %s\n", app.colorer.Green(app.Listener.Addr()))
		}
		return nil
	}
	if app.TLSListener == nil {
		l, err := newListener(s.Addr, app.ListenerNetwork)
		if err != nil {
			return err
		}
		app.TLSListener = tls.NewListener(l, s.TLSConfig)
	}
	if !app.HidePort {
		app.colorer.Printf("⇨ https server started on %s\n", app.colorer.Green(app.TLSListener.Addr()))
	}
	return nil
}

func (e *Application) serve() error {
	if e.TLSListener != nil {
		return e.Server.Serve(e.TLSListener)
	}
	return e.Server.Serve(e.Listener)
}

// ListenerAddr returns net.Addr for Listener
func (e *Application) ListenerAddr() net.Addr {
	e.startupMutex.RLock()
	defer e.startupMutex.RUnlock()
	if e.Listener == nil {
		return nil
	}
	return e.Listener.Addr()
}

// TLSListenerAddr returns net.Addr for TLSListener
func (e *Application) TLSListenerAddr() net.Addr {
	e.startupMutex.RLock()
	defer e.startupMutex.RUnlock()
	if e.TLSListener == nil {
		return nil
	}
	return e.TLSListener.Addr()
}

// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
func (app *Application) StartH2CServer(address string, h2s *http2.Server) (err error) {
	app.startupMutex.Lock()
	// Setup
	s := app.Server
	s.Addr = address
	app.colorer.SetOutput(app.Logger.Output())
	s.ErrorLog = app.StdLogger
	s.Handler = h2c.NewHandler(app, h2s)
	if app.Debug {
		app.Logger.SetLevel(log.DEBUG)
	}

	if !app.HideBanner {
		app.colorer.Printf(banner, app.colorer.Red("v"+Version), app.colorer.Blue(website))
	}

	if app.Listener == nil {
		app.Listener, err = newListener(s.Addr, app.ListenerNetwork)
		if err != nil {
			app.startupMutex.Unlock()
			return err
		}
	}
	if !app.HidePort {
		app.colorer.Printf("⇨ http server启动... on： %s\n", app.colorer.Green(app.Listener.Addr()))
	}
	app.startupMutex.Unlock()
	return s.Serve(app.Listener)
}

// Close immediately stops the server.
// It internally calls `http.Server#Close()`.
func (app *Application) Close() error {
	app.startupMutex.Lock()
	defer app.startupMutex.Unlock()
	if err := app.TLSServer.Close(); err != nil {
		return err
	}
	return app.Server.Close()
}

// Shutdown stops the server gracefully.
// It internally calls `http.Server#Shutdown()`.
func (app *Application) Shutdown(ctx stdContext.Context) error {
	app.startupMutex.Lock()
	defer app.startupMutex.Unlock()
	if err := app.TLSServer.Shutdown(ctx); err != nil {
		return err
	}
	return app.Server.Shutdown(ctx)
}

// NewHTTPError creates a new HTTPError instance.
func NewHTTPError(code int, message ...interface{}) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	if len(message) > 0 {
		he.Message = message[0]
	}
	return he
}

// Error makes it compatible with `error` interface.
func (he *HTTPError) Error() string {
	if he.Internal == nil {
		return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
	}
	return fmt.Sprintf("code=%d, message=%v, internal=%v", he.Code, he.Message, he.Internal)
}

// SetInternal sets error to HTTPError.Internal
func (he *HTTPError) SetInternal(err error) *HTTPError {
	he.Internal = err
	return he
}

// Unwrap satisfies the Go 1.13 error wrapper interface.
func (he *HTTPError) Unwrap() error {
	return he.Internal
}

// WrapHandler wraps `http.Handler` into `gz.HandlerFunc`.
func WrapHandler(h http.Handler) HandlerFunc {
	return func(c Context) error {
		h.ServeHTTP(c.Response(), c.Request())
		return nil
	}
}

// WrapMiddleware wraps `func(http.Handler) http.Handler` into `gz.MiddlewareFunc`
func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
	return func(next HandlerFunc) HandlerFunc {
		return func(c Context) (err error) {
			m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				c.SetRequest(r)
				c.SetResponse(NewResponse(w, c.Application()))
				err = next(c)
			})).ServeHTTP(c.Response(), c.Request())
			return
		}
	}
}

func (e *Application) findRouter(host string) *Router {
	if len(e.routers) > 0 {
		if r, ok := e.routers[host]; ok {
			return r
		}
	}
	return e.router
}

func handlerName(h HandlerFunc) string {
	t := reflect.ValueOf(h).Type()
	if t.Kind() == reflect.Func {
		return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
	}
	return t.String()
}

// // PathUnescape is wraps `url.PathUnescape`
// func PathUnescape(s string) (string, error) {
// 	return url.PathUnescape(s)
// }

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	if c, err = ln.AcceptTCP(); err != nil {
		return
	} else if err = c.(*net.TCPConn).SetKeepAlive(true); err != nil {
		return
	}
	// Ignore error from setting the KeepAlivePeriod as some systems, such as
	// OpenBSD, do not support setting TCP_USER_TIMEOUT on IPPROTO_TCP
	_ = c.(*net.TCPConn).SetKeepAlivePeriod(3 * time.Minute)
	return
}

func newListener(address, network string) (*tcpKeepAliveListener, error) {
	if network != "tcp" && network != "tcp4" && network != "tcp6" {
		return nil, ErrInvalidListenerNetwork
	}
	l, err := net.Listen(network, address)
	if err != nil {
		return nil, err
	}
	return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
}

func applyMiddleware(h HandlerFunc, middleware ...MiddlewareFunc) HandlerFunc {
	for i := len(middleware) - 1; i >= 0; i-- {
		h = middleware[i](h)
	}
	return h
}
